import os
import zipfile
import logging
import uuid
from datetime import datetime
from threading import Timer

from flask import Flask, request, send_file, render_template_string, jsonify, url_for
from werkzeug.utils import secure_filename
import pandas as pd

from main import ReportGenerator

# 创建日志记录器
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# 配置日志格式
log_formatter = logging.Formatter(
    fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
# 配置文件处理器
log_file = 'app.log'
file_handler = logging.FileHandler(log_file, encoding='utf-8')
file_handler.setFormatter(log_formatter)
file_handler.setLevel(logging.INFO)
# 添加处理器到日志记录器
logger.addHandler(file_handler)
logger.info('日志系统初始化完成')

# 创建 Flask 应用
app = Flask(__name__, static_folder='static', static_url_path='/static')
# 设置安全密钥
app.secret_key = os.environ.get('FLASK_SECRET_KEY', 'your-secret-key-here')
# 设置最大上传文件大小为 16MB
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024

HTML = '''
<!DOCTYPE html>
<html>
<head>
    <title>基因检测报告生成器</title>
    <meta charset="utf-8">
    <style>
        body { 
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        .container {
            text-align: center;
            padding: 20px;
            border: 1px solid #ccc;
            border-radius: 5px;
        }
        .btn {
            padding: 10px 20px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin: 10px;
        }
        .btn:hover {
            background-color: #45a049;
        }
        .progress {
            width: 100%;
            max-width: 600px;
            margin: 20px auto;
            display: none;
        }
        .progress-bar {
            width: 100%;
            height: 20px;
            background-color: #f0f0f0;
            border-radius: 10px;
            overflow: hidden;
        }
        .progress-bar-fill {
            height: 100%;
            background-color: #4CAF50;
            width: 0%;
            transition: width 0.3s ease;
        }
        .progress-text {
            margin-top: 10px;
            text-align: center;
        }
        .download-area {
            margin-top: 20px;
            display: none;
        }
        .download-link {
            color: #4CAF50;
            text-decoration: none;
            padding: 10px 20px;
            border: 2px solid #4CAF50;
            border-radius: 4px;
            display: inline-block;
        }
        .download-link:hover {
            background-color: #4CAF50;
            color: white;
        }
        .logo {
            max-width: 200px;
            margin: 20px auto;
            display: block;
        }
    </style>
</head>
<body>
    <div class="container">
        <img src="/static/icon.webp" alt="Logo" class="logo">
        <h1>基因检测报告生成器</h1>
        <form id="uploadForm" method="post" action="/generate" enctype="multipart/form-data">
            <div>
                <p>请选择Excel样本文件：</p>
                <input type="file" name="file" accept=".xlsx" required>
            </div>
            <div>
                <button type="submit" class="btn">生成报告</button>
            </div>
        </form>
        <div class="progress" id="progress">
            <div class="progress-bar">
                <div class="progress-bar-fill" id="progressBar"></div>
            </div>
            <div class="progress-text" id="progressText">准备生成报告...</div>
        </div>
        
        <div class="download-area" id="downloadArea">
            <p>报告已生成完成！</p>
            <a href="#" class="download-link" id="downloadLink">点击下载报告</a>
        </div>
    </div>
    <script>
        document.getElementById('uploadForm').onsubmit = function(e) {
            e.preventDefault();
            
            const formData = new FormData(this);
            const progress = document.getElementById('progress');
            const progressBar = document.getElementById('progressBar');
            const progressText = document.getElementById('progressText');
            const downloadArea = document.getElementById('downloadArea');
            const downloadLink = document.getElementById('downloadLink');
            
            // 重置状态
            progress.style.display = 'block';
            downloadArea.style.display = 'none';
            
            fetch('/generate', {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                if (data.status === 'success') {
                    // 显示下载区域和链接
                    downloadArea.style.display = 'block';
                    downloadLink.href = data.download_url;
                } else {
                    throw new Error(data.message || '生成报告失败');
                }
                progress.style.display = 'none';
            })
            .catch(error => {
                alert('错误：' + error.message);
                progress.style.display = 'none';
                downloadArea.style.display = 'none';
            });
            
            // 开始轮询进度
            const checkProgress = () => {
                fetch('/progress')
                .then(response => response.json())
                .then(data => {
                    progressBar.style.width = data.progress + '%';
                    progressText.textContent = data.message;
                    
                    if (data.progress < 100) {
                        setTimeout(checkProgress, 500);
                    }
                });
            };
            
            checkProgress();
        };
    </script>
</body>
</html>
'''

# 添加进度跟踪
progress_data = {
    'progress': 0,
    'message': '准备生成报告...',
    'total': 0,
    'current': 0
}

# 添加临时文件管理
TEMP_FILES = {}  # 存储临时文件信息：{file_id: {'path': path, 'created_at': datetime}}
TEMP_FILE_LIFETIME = 3600  # 临时文件保存时间（秒）


def cleanup_temp_files():
    """定期清理过期的临时文件"""
    logger.info("开始清理临时文件")
    current_time = datetime.now()
    expired_files = []
    
    for file_id, file_info in TEMP_FILES.items():
        if (current_time - file_info['created_at']).total_seconds() > TEMP_FILE_LIFETIME:
            try:
                if os.path.exists(file_info['path']):
                    os.remove(file_info['path'])
                    logger.info(f'已删除过期的临时文件: {file_info["path"]}')
                expired_files.append(file_id)
            except OSError as e:
                logger.error(f"删除临时文件时出错: {str(e)}")
    
    for file_id in expired_files:
        TEMP_FILES.pop(file_id)
    
    logger.info(f"清理完成，共删除 {len(expired_files)} 个过期文件")


# 设置定期清理任务
Timer(300, cleanup_temp_files).start()  # 每5分钟清理一次


@app.route('/')
def index():
    return render_template_string(HTML)


@app.route('/progress')
def get_progress():
    logger.debug(f"获取进度信息: {progress_data}")
    return jsonify(progress_data)


@app.route('/generate', methods=['POST'])
def generate():
    if 'file' not in request.files:
        logger.warning("没有文件被上传")
        return jsonify({'status': 'error', 'message': '请选择文件'})
    
    file = request.files['file']
    if file.filename == '':
        logger.warning("上传的文件名为空")
        return jsonify({'status': 'error', 'message': '没有选择文件'})
        
    if file:
        try:
            logger.info(f"开始处理上传的文件: {file.filename}")
            
            # 创建唯一的临时目录
            temp_id = str(uuid.uuid4())
            temp_base = os.path.join('temp', temp_id)
            upload_dir = os.path.join(temp_base, 'uploads')
            output_dir = os.path.join(temp_base, 'output')
            os.makedirs(upload_dir, exist_ok=True)
            os.makedirs(output_dir, exist_ok=True)
            logger.info(f"创建临时目录: {temp_base}")
            
            # 保存上传的文件
            filename = secure_filename(file.filename)
            input_path = os.path.join(upload_dir, filename)
            file.save(input_path)
            logger.info(f"文件已保存到: {input_path}")
            
            # 读取Excel文件中的样本数据
            logger.info("开始读取Excel文件")
            samples = pd.read_excel(input_path).to_dict('records')
            progress_data['total'] = len(samples)
            logger.info(f"读取到 {len(samples)} 个样本")
            
            # 生成报告
            logger.info("开始生成报告")
            report_generator = ReportGenerator()
            for i, sample in enumerate(samples, 1):
                logger.info(f"正在处理第 {i}/{len(samples)} 个样本")
                try:
                    report_generator.generate_report(sample, output_dir)
                    progress_data['current'] = i
                    progress_data['progress'] = int(i * 100 / len(samples))
                    progress_data['message'] = f'正在生成报告 ({i}/{len(samples)})'
                    logger.info(f"进度更新: {progress_data['progress']}% - {progress_data['message']}")
                except Exception as e:
                    logger.error(f"处理样本 {i} 时出错: {str(e)}")
                    raise
            
            # 打包报告
            logger.info("开始打包报告")
            progress_data['message'] = '正在打包报告...'
            zip_path = os.path.join(temp_base, 'reports.zip')
            with zipfile.ZipFile(zip_path, 'w') as zipf:
                for root, dirs, files in os.walk(output_dir):
                    for file in files:
                        file_path = os.path.join(root, file)
                        arcname = os.path.relpath(file_path, output_dir)
                        zipf.write(file_path, arcname)
                        logger.debug(f"添加文件到压缩包: {arcname}")
            
            logger.info(f"报告打包完成: {zip_path}")
            
            # 记录临时文件信息
            TEMP_FILES[temp_id] = {
                'path': zip_path,
                'created_at': datetime.now()
            }
            
            progress_data['progress'] = 100
            progress_data['message'] = '报告生成完成'
            logger.info("报告生成流程完成")
            
            # 返回下载链接
            download_url = url_for('download_file', file_id=temp_id, _external=True)
            logger.info(f"生成下载链接: {download_url}")
            return jsonify({
                'status': 'success',
                'download_url': download_url
            })
            
        except Exception as e:
            logger.error(f"生成报告时出错: {str(e)}", exc_info=True)
            return jsonify({
                'status': 'error',
                'message': f'生成报告时出错：{str(e)}'
            })


@app.route('/download/<file_id>')
def download_file(file_id):
    logger.info(f"请求下载文件: {file_id}")
    if file_id not in TEMP_FILES:
        logger.warning(f"文件不存在或已过期: {file_id}")
        return '文件不存在或已过期', 404
    
    file_info = TEMP_FILES[file_id]
    if not os.path.exists(file_info['path']):
        logger.warning(f"文件已被删除: {file_info['path']}")
        TEMP_FILES.pop(file_id)
        return '文件不存在或已过期', 404
    
    logger.info(f"开始下载文件: {file_info['path']}")
    return send_file(
        file_info['path'],
        mimetype='application/zip',
        as_attachment=True,
        download_name='reports.zip'
    )


def run_server():
    # 生产环境配置
    port = int(os.environ.get('PORT', 5001))
    app.run(
        host='0.0.0.0',  # 允许外部访问
        port=port,
        debug=False,     # 关闭调试模式
        threaded=True    # 启用多线程
    )


if __name__ == '__main__':
    run_server()
